﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace IWMAG.Scripting.DevelopmentEnvironment.CodeCompletion
{
    internal class DirectedAcyclicList<T> : ILists<T>
    {
        public DirectedAcyclicList()
        {
            root = new DAWGNode();
            Reset();
            
        }
        private DAWGNode root;
        private Stack<DAWGNode> curStack = new Stack<DAWGNode>();
        private class DAWGNode
        {
            public bool IsEndOfStream { get; set; }

            public T Value { get; set; }

            private Lazy<SortedDictionary<T, DAWGNode>> _children = new Lazy<SortedDictionary<T, DAWGNode>>(() => new SortedDictionary<T, DAWGNode>());
            public SortedDictionary<T, DAWGNode> Children
            {
                get
                {
                    return _children.Value;
                }
            }

            public IEnumerable<IEnumerable<T>> GetChildrenEnumerable()
            {
                
                var thisVal = Enumerable.Repeat(Value, 1);

                if (this.IsEndOfStream)
                {
                    yield return thisVal;
                }

                foreach (var item in this.Children.Values)
                {
                    foreach (var item2 in item.GetChildrenEnumerable())
                    {
                        yield return thisVal.Concat(item2);
                    }
                }

                yield break;


            }
        }

        public void Add(IEnumerable<T> s)
        {
            DAWGNode cur = root;
            foreach (var item in s)
            {
                if (!cur.Children.ContainsKey(item))
                {
                    var n = new DAWGNode();
                    n.Value = item;
                    cur.Children[item] = n;
                }
                cur = cur.Children[item];
            }

            cur.IsEndOfStream = true;
        }

        public void Remove(IEnumerable<T> s)
        {
            throw new NotImplementedException();
        }

        public bool Contains(IEnumerable<T> s)
        {
            DAWGNode cur = root;
            foreach (var item in s)
            {
                if (!cur.Children.ContainsKey(item))
                {
                    return false;
                }
                cur = cur.Children[item];
            }

            return cur.IsEndOfStream;
        }

        public void Push(T c)
        {
            if (curStack.Count == 0)
            {
                var t = root;
                if (t.Children.ContainsKey(c))
                {
                    curStack.Push(t.Children[c]);
                }
                else
                {
                    curStack.Push(null);
                }
            }
            else if (curStack.Peek() == null)
            {
                curStack.Push(null);
            }
            else
            {
                var t = curStack.Peek();
                if (t.Children.ContainsKey(c))
                {
                    curStack.Push(t.Children[c]);
                }
                else
                {
                    curStack.Push(null);
                }
            }
        }

        public void Push(IEnumerable<T> s)
        {
            foreach (var item in s)
            {
                Push(item);
            }
        }

        public IEnumerable<IEnumerable<T>> EnumerateList()
        {
            if (curStack.Count == 0)
            {
                var t = Enumerable.Empty<IEnumerable<T>>();
                foreach (var item in root.Children.Values)
                {
                    t = t.Concat(item.GetChildrenEnumerable());
                }

                return t;
            }
            if (curStack.Peek() == null)
            {
                return Enumerable.Empty<IEnumerable<T>>();
            }

            var t2 = Enumerable.Empty<IEnumerable<T>>();
            foreach (var item in curStack.Peek().Children.Values)
            {
                t2 = t2.Concat(item.GetChildrenEnumerable());
            }


            return t2;
        }

        public void Reset()
        {
            curStack.Clear();
        }


        public IEnumerable<IEnumerable<T>> EnumerateListWithPrevious()
        {
            var c = Enumerable.Empty<T>();
            foreach (var item in curStack.Where(i => i!= null))
            {
                c = c.Concat(Enumerable.Repeat(item.Value, 1));
            }

            c = c.Reverse();

            foreach (var item in EnumerateList())
            {
                yield return c.Concat(item);
            }

            yield break;
        }
    }
}
